const util = require('util')
const https = require('https')
const http = require('http')
const path = require('path')
const formstream = require('formstream')
const {
    stat
} = require('fs')
const statAsync = util.promisify(stat)

const {
    URL
} = require('url')
const qs = require('querystring')

class Request {
    constructor() {}

    /**
     * get 请求
     * @param {*请求地址 不带参数} uri 
     * @param {*请求参数} data 
     */
    async get(uri, data = {}) {
        return new Promise((resolve, reject) => {
            let Uri = new URL(uri)
            // 组合search 有search 带? 拼接data 无search  直接拼接data
            let search = `${Uri.search ? Uri.search + '&' : '?'}${qs.stringify(data)}`

            const protocol = Uri.protocol == 'http:' ? http : https
            const options = {
                hostname: Uri.hostname,
                path: `${Uri.pathname}${search}`,
                port: Uri.port,
                method: 'GET'
            }

            const req = protocol.request(options, (res) => {
                let body = ''
                res.setEncoding('utf8')
                res.on('data', (chunk) => {
                    body += chunk
                })
                res.on('end', function () {
                    try {
                        let data = JSON.parse(body)
                        return resolve(data)
                    } catch (err) {
                        console.trace(err)
                        return reject(err)
                    }
                })
            })

            req.on('error', (err) => {
                console.error(err)
                return reject(err)
            })
            req.setTimeout(120000, function () {
                req.abort()
                console.log('Request timeout')
                return false
            })

            req.end()
        }).catch(err => {
            throw new Error(err)
        })
    }
    /**
     * post请求
     * @param {*请求地址 不带参数} uri 
     * @param {*请求参数} data 
     */
    async post(uri, data) {
        return new Promise((resolve, reject) => {
            let Uri = new URL(uri)
            const postData = qs.stringify(data)
            const search = Uri.search
            const protocol = Uri.protocol == 'http:' ? http : https
            const options = {
                hostname: Uri.hostname,
                path: `${Uri.pathname}${search}`,
                port: Uri.port,
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Content-Length': Buffer.byteLength(postData)
                }
            }
            const req = protocol.request(options, (res) => {
                let body = ''
                res.setEncoding('utf8')
                res.on('data', (chunk) => {
                    body += chunk
                })
                res.on('end', function () {
                    try {
                        let data = JSON.parse(body)
                        resolve(data)
                    } catch (err) {
                        console.trace(err)
                        reject(err)
                    }
                })
            })

            req.on('error', (err) => {
                console.error(err)
                reject(err)
            })
            req.setTimeout(120000, function () {
                req.abort()
                console.log('Request timeout')
                return false
            })
            req.write(postData)
            req.end()
        }).catch(err => {
            throw new Error(err)
        })
    }
    /**
     * post json请求
     * @param {*请求地址 不带参数} uri 
     * @param {*请求参数} data 
     */
    async json(uri, data) {
        return new Promise((resolve, reject) => {
            let Uri = new URL(uri)
            const postData = JSON.stringify(data)
            const search = Uri.search
            const protocol = Uri.protocol == 'http:' ? http : https
            const options = {
                hostname: Uri.hostname,
                path: `${Uri.pathname}${search}`,
                port: Uri.port,
                method: 'POST',
                json: true,
                headers: {
                    'Accept': 'application/jsonversion=2.0',
                    'Content-Type': 'application/json',
                    'Content-Length': Buffer.byteLength(postData)
                }
            }
            const req = protocol.request(options, (res) => {
                let body = ''
                res.setEncoding('utf8')
                res.on('data', (chunk) => {
                    body += chunk
                })
                res.on('end', function () {
                    try {
                        let data = JSON.parse(body)
                        resolve(data)
                    } catch (err) {
                        console.trace(err)
                        reject(err)
                    }
                })
            })

            req.on('error', (err) => {
                console.error(err)
                reject(err)
            })
            req.setTimeout(120000, function () {
                req.abort()
                console.log('Request timeout')
                return false
            })
            req.write(postData)
            req.end()
        }).catch(err => {
            throw new Error(err)
        })
    }
    /**
     * file请求
     * @param {*请求地址 不带参数} uri 
     * @param {*请求参数} data 
     */
    async file(uri, data) {
        const stat = await statAsync(data['file'])
        const form = formstream()
        form.file('media', data['file'], path.basename(data['file']), stat.size)
        return new Promise((resolve, reject) => {
            let Uri = new URL(uri)
            const postData = qs.stringify(data)
            const search = Uri.search
            const protocol = Uri.protocol == 'http:' ? http : https
            const options = {
                hostname: Uri.hostname,
                path: `${Uri.pathname}${search}`,
                port: Uri.port,
                method: 'POST',
                headers: form.headers()
            }
            const req = protocol.request(options, (res) => {
                let body = ''
                res.setEncoding('utf8')
                res.on('data', (chunk) => {
                    body += chunk
                })
                res.on('end', function () {
                    try {
                        let data = JSON.parse(body)
                        resolve(data)
                    } catch (err) {
                        console.trace(err)
                        reject(err)
                    }
                })
            })

            req.on('error', (err) => {
                console.error(err)
                reject(err)
            })
            req.setTimeout(120000, function () {
                req.abort()
                console.log('Request timeout')
                return false
            })
            form.pipe(req)
        }).catch(err => {
            throw new Error(err)
        })
    }
}

module.exports = new Request()